﻿using System;

namespace GxFramework
{
    public enum WorkStatus
    {
        Idle =0,
        Running=1,
        Failure=3,
        Success=4,
    }

    /// <summary>
    /// 1.工作对象：行为树种的基类，有闲置、运行中、执行失败、执行成功等状态
    /// 2.行为树中结点执行和更新有2中方式，自顶向下和自底向上：
    /// 自顶向下：父节点执行（进入和更新）的时候的时候会执行（启动或更新）当前子节点，
    /// 自底向上：子节点完成（Finish）的时候通知父节点进行更新，并逐级向上进行同样的处理直到遇到树根结点或者没完成的结点
    /// </summary>
    public class WorkObject
    {
        int _id;
        WorkStatus _status = WorkStatus.Idle;
        BrankWork _parent;
        public int id { get { return _id; } }
        public WorkStatus status { get { return _status; } }
        public BrankWork parent { get { return _parent; } }
        public bool isRunning { get { return status == WorkStatus.Running; } }
        public bool isDone { get { return status != WorkStatus.Idle && status != WorkStatus.Running; } }
        public bool isSuccess { get { return status == WorkStatus.Success; } }
        public bool isFailure { get { return status == WorkStatus.Failure; } }

        public WorkObject root
        {
            get {
                var p = this;
                while (null != p.parent)
                    p = p.parent;
                return p;
            }
        }
        public BehaviourTree behavirouTree { get { return root as BehaviourTree; } }
        public FSM stachMachine { get { return root as FSM; } }
        public void SetId(int value)
        {
            _id = value;
        }
        internal void SetStatus(WorkStatus value)
        {
            _status = value;
        }
        internal void SetParent(CompositeWork value)
        {
            _parent = value;
        }
        public bool IsAncestor(CompositeWork container)
        {
            var p = this.parent;
            while (null != p)
            {
                if (p == container)
                    return true;
                p = p.parent;
            }
            return false;
        }
        public WorkStatus Exec()
        {
            return Exec(WorkStatus.Running);
        }
        public WorkStatus Exec(WorkStatus status)
        {
            bool isEnter = false;
            if (this.status == WorkStatus.Running)
                isEnter = true;
            else
            {
                this.SetStatus(WorkStatus.Idle);
                isEnter = this.EnterTest();
            }
            if (isEnter)
            {
                bool isValid = this.CheckParentUpdatePreconditions();
                if (isValid)
                {
                    var updateStatus = ProcessUpdate(status);
                    this.SetStatus(updateStatus);
                }
                else
                {
                    this.SetStatus(WorkStatus.Failure);
                    if (null != this.GetCurrentWork())
                    {
                        ProcessUpdate(WorkStatus.Failure);
                    }
                }
                if (this.status != WorkStatus.Running)
                    this.ProcessExit(this.status);
                else
                {
                    //把自己标记为父级分支节点的当前任务
                    var brankNode = GetTopManageBranchTask();
                    if (null != brankNode)
                        brankNode.SetCurrentWork(this);
                }
            }
            else
                this.SetStatus(WorkStatus.Failure);
            return this.status;
        }
        virtual public WorkObject GetCurrentWork()
        {
            return null;
        }
        virtual public void SetCurrentWork(WorkObject work)
        {
        }
        virtual protected bool OnEnter()
        {
            return true;
        }
        virtual protected void OnExit(WorkStatus status)
        {
        }
        virtual protected WorkStatus ProcessUpdate(WorkStatus status)
        {
            return Update(status);
        }
        virtual protected WorkStatus Update(WorkStatus status)
        {
            return WorkStatus.Success;
        }
        public bool EnterTest()
        {
            var bResult = CheckPreconditions(false);
            if (bResult)
            {
                this.SetCurrentWork(null);
                bResult = OnEnter();
            }
            return bResult;
        }
        public void ProcessExit(WorkStatus status)
        {
            this.OnExit(status);
        }
        virtual protected bool CheckPreconditions(bool isAlive)
        {
            return true;
        }
        //检测当前节点到根节点的更新前置条件:从上到下
        bool CheckParentUpdatePreconditions()
        {
            if(!this.CheckPreconditions(true))
                return false;

            if (null != this.parent)
            {
                var nodes = new System.Collections.Generic.List<WorkObject>();
                var node = this.parent;
                while (null != node)
                {
                    nodes.Add(node);
                    node = node.parent;
                }
                for (int i = nodes.Count - 1; i >= 0; --i)
                {
                    if (!nodes[i].CheckPreconditions(true))
                        return false;
                }
            }
            return true;
        }
        BrankWork GetTopManageBranchTask()
        {
            BrankWork ret = null;
            var p = this.parent;

            while (null != p)
            {
                if (p is BehaviourTree)
                {
                    ret = p;
                    break;
                }
                ret = p;
                p = p.parent;
            }
            return p;
        }
        public virtual int GetNextStateId()
        {
            return -1;
        }
        virtual public void Initialize()
        {
 
        }
        virtual public void Clear()
        {
            this.SetStatus(WorkStatus.Idle);
            this.SetParent(null);
        }
        /// <summary>
        /// 事件链：沿父结点冒泡处理事件,直至返回false
        /// 如果在运行中且事件不敏感返回false
        /// </summary>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public virtual bool OnEvent(string eventName)
        {
            bool hasRegisterCurEvent = false;
            if (this.status == WorkStatus.Running && hasRegisterCurEvent)
            {
                return false;
            }
            return true;
        }
        public void Finish(bool succeed)
        {
            this.SetStatus(succeed ? WorkStatus.Success : WorkStatus.Failure);
            ProcessFinish(succeed);
        }
        virtual protected WorkStatus ProcessFinish(bool succeed)
        {
            return WorkStatus.Success;
        }
    }
}